#include "target.h"
#include "service_scheduling.h"
#include "service_uart.h"
#include "service_time.h"
#include "protocol.h"
#include "service_lightdot_storage.h"
#include "CRC.h"

/*
 * Protocol.c
 *
 *  Created on: 24/03/2010
 *      Author: bruno.silva
 */
UartHandle handleUart;

#define SIZE_MEMORY 264
#define SIZE_COMMAND 4
#define ID_CONTROLLER "  LightDot 9.3  "
#define	ACK_CMD		  '*'
#define NACK_CMD	  '#'


#define	CI_INCOMPLETE			0x100	// 1 = Continue
#define	CI_BMP_WIDTH			0x101	// Widht
#define CI_BMP_ROLL_TYPE		0x102	// Roll Type
#define	CI_BMP_FLAGS			0x103	// Flags
#define	CI_LCD_MSG_INDEX		0x104	// LCD Index
#define	CI_CRC16_CHECK_VALUE	0x106	// CRC16


static U8 pageMemory[SIZE_MEMORY];//TODO insert constant
static U8 command[SIZE_COMMAND];//TODO insert constant

void protocol_init(void)
{
	handleUart = service_uart_open(1);
}

BOOL protocol_verify_command(U8 * command)
{
	if (command[0] == '/' && command[1] == '/' && command[2] == command[3])	{		
		return TRUE;
	} else {		
		return FALSE;
	}
}

void protocol_resetController(void)
{
	service_uart_sendByte(handleUart, ACK_CMD);
}

BOOL protocol_sendId(void)
{								
	U16 crc;
	static U8 tempR;

	service_CRC16Init(&crc);
	service_uart_sendStream(handleUart, ID_CONTROLLER, 16);
	service_CRC16UpdateStream(ID_CONTROLLER, 16, &crc);
	service_uart_sendByte(handleUart, (U8) (crc >> 8));
	service_uart_sendByte(handleUart, (U8) (crc & 0xFF));

	if(service_uart_receiveByte(handleUart, &tempR) && tempR == ACK_CMD)
	{
		//DEBUG service_uart_sendByte(handleUart, '!');
		return TRUE;
	}

	return FALSE;
}
		   
void protocol_receivePage()
{
	U8 byteTemp, size;
	U16 crc16, page, crcReceived;

	service_uart_sendByte(handleUart, ACK_CMD);

	while(TRUE)
	{
		//Receive page MSB
		service_CRC16Init(&crc16);

		if(!service_uart_receiveByte(handleUart, &byteTemp)) return;

		page  = ((U16)byteTemp) << 8;
		service_CRC16UpdateByte(byteTemp, &crc16);

		//Receive page LSB
		if(!service_uart_receiveByte(handleUart, &byteTemp)) return;

		page  |= ((U16)byteTemp);
		service_CRC16UpdateByte(byteTemp, &crc16);

		//Receive size
		if(!service_uart_receiveByte(handleUart, &byteTemp)) return;

		size  = byteTemp;
		service_CRC16UpdateByte(byteTemp, &crc16);

		//Receive
		if(!service_uart_receiveByte(handleUart, &byteTemp)) return;
		crcReceived = ((U16)byteTemp) << 8;

		//Receive
		if(!service_uart_receiveByte(handleUart, &byteTemp)) return;
		crcReceived |= ((U16)byteTemp);

		//Receive crc MSB
		if(crcReceived == crc16)
		{
			service_uart_sendByte(handleUart, ACK_CMD);
			break;
		}

		service_uart_sendByte(handleUart, NACK_CMD);
	}

	while(TRUE)
	{
		U16 index;

		service_CRC16Init(&crc16);

		for (index = 0; index <= size; index++)
		{
			//Receive byte
			if(!service_uart_receiveByte(handleUart, &byteTemp)) return;
			
			pageMemory[index] = byteTemp;
			service_CRC16UpdateByte(byteTemp, &crc16);
		}

		for(index = CI_INCOMPLETE; index < CI_CRC16_CHECK_VALUE; index++)
		{
			if(!service_uart_receiveByte(handleUart, &byteTemp)) return;

			pageMemory[index] = byteTemp;
			service_CRC16UpdateByte(byteTemp, &crc16);
		}

		//Receive
		if(!service_uart_receiveByte(handleUart, &byteTemp)) return;
		crcReceived = ((U16)byteTemp) << 8;

		//Receive
		if(!service_uart_receiveByte(handleUart, &byteTemp)) return;
		crcReceived |= ((U16)byteTemp);

		//Receive crc MSB
		if(crcReceived == crc16)
		{
			service_uart_sendByte(handleUart, ACK_CMD);
			service_lightdos_storage_write(page, 0, pageMemory, SIZE_MEMORY);
			break;
		}
				
		service_uart_sendByte(handleUart, NACK_CMD);		
	}
}


void receive_command()
{
	if(service_uart_receiveStream(handleUart, command, SIZE_COMMAND) && protocol_verify_command(command))
	{
		protocol_command command_ix = (protocol_command) command[2];

		switch (command_ix) {
			case protocol_controllerId:
				protocol_sendId();
				break;
			case protocol_reset:
				protocol_resetController();
				break;
			case protocol_receiveFlashPage:
				protocol_receivePage();
			default:
				break;
		}
	}
	else
	{
		//service_uart_sendByte(handleUart, 'N');//DEBUG
		//Turn Command Invalid!
		command[0] =0xFF;
	}
}

service_scheduling_TASK_FUNCTION_DECLARATION(protocolProcess, args)
{
//	U8 temp;   
//	
//	if(service_uart_receiveByte(handleUart, &temp))
//	{
//		service_uart_sendByte(handleUart, temp);
//	}
	receive_command();
//	service_uart_sendByte(handleUart, 'C');
}
